﻿Imports System.Threading
Imports System.Text
Imports System.Runtime.InteropServices

Public Class RFID
    Private commtype As RFIDLIB.COMMTYPE
    Private iret As Integer
    Private hreader As UIntPtr
    ''' <summary>
    ''' 标签连接状态
    ''' </summary>
    Private hTag As UIntPtr
    Private antennaCount As UInteger
    ''' <summary>
    ''' 异步输出读标签信息
    ''' </summary>
    Private asyncReport As Boolean
    Private _shouldStop As Boolean
    ''' <summary>
    ''' 读卡器打开状态
    ''' </summary>
    Private openState As Byte
    Private inventoryState As Byte
    Private readerType As Byte
    Private AntennaSel As Byte()
    ''' <summary>
    ''' 在ISO15693 Inventory过程中是否匹配AFI值。0：否 ；1：是
    ''' </summary>
    Private enableAFI As Byte = 0
    ''' <summary>
    ''' AFI值
    ''' </summary>
    Private AFI As Byte = 0
    Private AntennaSelCount As Byte
    Private onlyNewTag As Byte
    Private InvenThread As Thread
    Private airInterfaceProtList As ArrayList = New ArrayList()
    Private callbackDelegate As RFIDLIB.RFIDLIB_EVENT_CALLBACK = New RFIDLIB.RFIDLIB_EVENT_CALLBACK(AddressOf CallBack)
    Private Delegate Sub delegateInventoryFinishCallback()
    Private Delegate Sub InventoryTagReportEventHandler(aip_id As UInteger, tag_id As UInteger, ant_id As UInteger, dsfid As Byte, uid As Byte())
    Private Delegate Sub InventoryTagDataReadEventHandler(uid As Byte())
    Private Delegate Sub delegate_tag_report_handle(AIPType As UInteger, tagType As UInteger, antID As UInteger, dsfid As Byte, uid As Byte(), uidlen As Byte)

    Private Function Tag_inventory(AIType As Byte,
                                  AntennaSelCount As Byte,
                                  AntennaSel As Byte(),
                                enable15693 As Boolean,
                                 enable14443A As Boolean,
                                   enableAFI As Byte,
                                  afiVal As Byte,
                                 tagReportHandler As delegate_tag_report_handle,
                                 ByRef nTagCount As UInteger)
        Dim iret As Integer
        Dim InvenParamSpecList As UIntPtr = RFIDLIB.Rfidlib_reader.RDR_CreateInvenParamSpecList()
        If InvenParamSpecList.ToUInt64() <> 0 Then
            If enable15693 Then
                RFIDLIB.Rfidlib_aip_iso15693.ISO15693_CreateInvenParam(InvenParamSpecList, 0, enableAFI, AFI, 0)
            End If
        End If
        nTagCount = 0
DO_INVENTORY_LABEL:
        iret = RFIDLIB.Rfidlib_reader.RDR_TagInventory(hreader, AIType, AntennaSelCount, AntennaSel, InvenParamSpecList)
        If iret = 0 OrElse iret = -21 Then
            nTagCount += RFIDLIB.Rfidlib_reader.RDR_GetTagDataReportCount(hreader)
            Dim TagDataReport As UIntPtr = CType(0, UIntPtr)
            TagDataReport = RFIDLIB.Rfidlib_reader.RDR_GetTagDataReport(hreader, RFIDLIB.Rfidlib_def.RFID_SEEK_FIRST)
            While (TagDataReport.ToUInt64() > 0)
                Dim aip_id As UInteger = 0
                Dim tag_id As UInteger = 0
                Dim ant_id As UInteger = 0
                Dim dsfid As Byte = 0
                Dim uidlen As Byte = 0
                Dim uid As Byte() = New Byte(7) {}
                iret = RFIDLIB.Rfidlib_aip_iso15693.ISO15693_ParseTagDataReport(TagDataReport, aip_id, tag_id, ant_id, dsfid, uid)
                If iret = 0 Then
                    uidlen = 8
                    Dim pList As Object() = {aip_id, tag_id, ant_id, dsfid, uid, uidlen}
                    Invoke(tagReportHandler, pList)
                End If
                TagDataReport = RFIDLIB.Rfidlib_reader.RDR_GetTagDataReport(hreader, RFIDLIB.Rfidlib_def.RFID_SEEK_NEXT)
            End While
            If iret = -21 Then
                AIType = RFIDLIB.Rfidlib_def.AI_TYPE_CONTINUE
                GoTo DO_INVENTORY_LABEL
            End If
            iret = 0
        End If
        If InvenParamSpecList <> 0 Then RFIDLIB.Rfidlib_data_node.DNODE_Destroy(InvenParamSpecList)
        Return iret
    End Function

    Public Sub DoInventory()
        If asyncReport Then
            RFIDLIB.Rfidlib_reader.RDR_EnableAsyncTagReportOutput(hreader, 2, 0, CType(0, UIntPtr), callbackDelegate)
        Else
            RFIDLIB.Rfidlib_reader.RDR_DisableAsyncTagReportOutput(hreader)
        End If
        Dim enISO15693, enISO14443a As Boolean
        Dim cbTagReportHandle = New delegate_tag_report_handle(AddressOf Dele_tag_report_handler)
        For i = 0 To airInterfaceProtList.Count - 1
            Dim aip As RFIDLIB.CSupportedAirProtocol = airInterfaceProtList(i)
            If aip.m_en Then
                If aip.m_ID = RFIDLIB.Rfidlib_def.RFID_APL_ISO15693_ID Then
                    enISO15693 = True
                ElseIf aip.m_ID = RFIDLIB.Rfidlib_def.RFID_APL_ISO14443A_ID Then
                    enISO14443a = True
                End If
            End If
        Next
        Dim iret As Integer
        Dim AIType As Byte = RFIDLIB.Rfidlib_def.AI_TYPE_NEW
        If onlyNewTag = 1 Then
            AIType = RFIDLIB.Rfidlib_def.AI_TYPE_CONTINUE
        End If
        While Not _shouldStop
            Dim nTagCount As UInteger = 0
            iret = Tag_inventory(AIType, AntennaSelCount, AntennaSel, enISO15693, enISO14443a, enableAFI, AFI, cbTagReportHandle, nTagCount)
            If iret = 0 Then
                '盘点成功
            End If
            AIType = RFIDLIB.Rfidlib_def.AI_TYPE_NEW
            If onlyNewTag = 1 Then
                AIType = RFIDLIB.Rfidlib_def.AI_TYPE_CONTINUE
            End If
        End While
        Dim pFinishList As Object() = {}
        Invoke(New delegateInventoryFinishCallback(AddressOf InventoryFinishCallback), pFinishList)
        RFIDLIB.Rfidlib_reader.RDR_ResetCommuImmeTimeout(hreader)
    End Sub

    Private Sub Dele_tag_report_handler(AIPType As UInteger, tagType As UInteger, antID As UInteger, dsfid As Byte, uid As Byte(), uidlen As Byte)
        Dim strUid As String = BitConverter.ToString(uid, 0, uidlen).Replace("-", String.Empty)
        Dim e As New RFIDEventArgs With {
            .AipId = AIPType,
            .TagId = tagType,
            .AntId = antID,
            .DSFID = dsfid,
            .UID = strUid,
            .UIDHEX = uid
        }
        RaiseEvent GetTabInfoEvent(Me, e)
        If asyncReport = False Then
            Dim pList As Object() = {uid}
            Invoke(New InventoryTagDataReadEventHandler(AddressOf ReadData), pList)
        End If
    End Sub

    Public Sub InventoryFinishCallback()
        '盘点标签结束后的UI线程操作
        inventoryState = 0
        'Me.ParentForm.Close()
    End Sub

    ''' <summary>
    ''' 异步盘点
    ''' </summary>
    ''' <param name="wparam"></param>
    ''' <param name="lparam"></param>
    Public Sub CallBack(wparam As UIntPtr, lparam As UIntPtr)
        Dim iret As Integer
        Dim aip_id As UInteger = 0
        Dim tag_id As UInteger = 0
        Dim ant_id As UInteger = 0
        Dim dsfid As Byte = 0
        Dim uid As Byte() = New Byte(7) {}
        iret = RFIDLIB.Rfidlib_aip_iso15693.ISO15693_ParseTagDataReport(lparam, aip_id, tag_id, ant_id, dsfid, uid)
        If iret = 0 Then
            Dim uidLen As Byte = 8
            Dim pList As Object() = {aip_id, tag_id, ant_id, dsfid, uid, uidLen}
            Dim cbTagReportHandle = New delegate_tag_report_handle(AddressOf Dele_tag_report_handler)
            Invoke(cbTagReportHandle, pList)
        End If
    End Sub
    ''' <summary>
    ''' RFID扫描初始化
    ''' </summary>
    ''' <remarks>RFID扫描初始化</remarks>
    Public Sub StartInventory()
        hTag = CType(0, UIntPtr)
        onlyNewTag = 0
        asyncReport = False
        _shouldStop = False
        InvenThread = New Thread(AddressOf DoInventory)
        InvenThread.Start()
        inventoryState = 1
    End Sub
    Public Sub Open()
        RFIDLIB.Rfidlib_reader.RDR_LoadReaderDrivers("")
        iret = RFIDLIB.Rfidlib_reader.RDR_Open(ConnString, hreader)
        If iret = 0 Then
            antennaCount = RFIDLIB.Rfidlib_reader.RDR_GetAntennaInterfaceCount(hreader)
            Dim index As UInteger = 0
            Dim AIType As UInteger
            While True
                Application.DoEvents()
                AIType = 0
                iret = RFIDLIB.Rfidlib_reader.RDR_GetSupportedAirInterfaceProtocol(hreader, index, AIType)
                If iret <> 0 Then
                    Exit While
                End If
                Dim namebuf As New StringBuilder()
                namebuf.Append(ControlChars.NullChar, 128)
                RFIDLIB.Rfidlib_reader.RDR_GetAirInterfaceProtName(hreader, AIType, namebuf, CType(namebuf.Capacity, UInteger))

                Dim aip As New RFIDLIB.CSupportedAirProtocol With {
                    .m_ID = AIType,
                    .m_name = namebuf.ToString(),
                    .m_en = True
                }
                airInterfaceProtList.Add(aip)
                index += 1
            End While
            openState = 1
            Call Beep()
        Else
            MsgBox("读卡器初始化失败，错误代码:" & iret, MsgBoxStyle.Exclamation, "警告")
        End If
    End Sub
    Public Sub StopInventory()
        _shouldStop = True
        RFIDLIB.Rfidlib_reader.RDR_SetCommuImmeTimeout(hreader)
    End Sub
    Public Sub Close()
        Call StopInventory()

        If hTag <> CType(0, UIntPtr) Then
            iret = RFIDLIB.Rfidlib_reader.RDR_DisconnectAllTags(hreader)
            While iret <> 0
                iret = RFIDLIB.Rfidlib_reader.RDR_DisconnectAllTags(hreader)
            End While
            hTag = 0
        End If
        iret = RFIDLIB.Rfidlib_reader.RDR_Close(hreader)
        If iret = 0 Then
            hreader = CType(0, UIntPtr)
            openState = 0
        Else
            MessageBox.Show("fail")
        End If
    End Sub

#Region "Propertys"
    ''' <summary>
    ''' 获取标签ID时引发事件
    ''' </summary>
    Public Event GetTabInfoEvent(sender As Object, e As RFIDEventArgs)

    Public Event Status(sender As Object, e As RFIDStatusEventArgs)
    ''' <summary>
    ''' 连接字符串
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks>连接字符串</remarks>
    Public Property ConnString As String
    ''' <summary>
    ''' 连接设备类型
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks>连接设备类型</remarks>
    Public Property ConnType As RFIDLIB.COMMTYPE
        Get
            Return commtype
        End Get
        Set(value As RFIDLIB.COMMTYPE)
            If value = RFIDLIB.COMMTYPE.USB Then
                ConnString = "RDType=RD100;CommType=USB;AddrMode=0;SerNum="
            ElseIf value = RFIDLIB.COMMTYPE.COM Then
                ConnString = "RDType=RD201;CommType=COM;COMName=COM1;BaudRate=38400;Frame=8E1;BusAddr=255"
            End If
            commtype = value
        End Set
    End Property

    ''' <summary>
    ''' 获取设备信息
    ''' </summary>
    ''' <returns></returns>
    Public ReadOnly Property DrvInfo As String
        Get
            Return GetDrvInfo()
        End Get
    End Property

#End Region

    Private Sub RFID_ControlAdded(sender As Object, e As System.Windows.Forms.ControlEventArgs) Handles Me.ControlAdded
        Visible = False
    End Sub

    Public Sub SetGetConfig()
        Dim iref As UIntPtr = RFIDLIB.Rfidlib_reader.RDR_CreateSetGetConfigItemList()
        RFIDLIB.Rfidlib_reader.RDR_GetConfig(hreader, iref)

        Dim cfgBuff As Byte() = New Byte(7) {}
        Dim nSize = CType(cfgBuff.GetLength(0), UInteger)
        Dim result As Integer = RFIDLIB.Rfidlib_reader.RDR_ConfigBlockRead(hreader, 4, cfgBuff, nSize)
        If result = 0 Then
            Console.WriteLine(BitConverter.ToString(cfgBuff))
            Dim wrtBuff As Byte() = New Byte(7) {0, 0, 0, 0, 0, 0, 0, 3}
            If cfgBuff.SequenceEqual(wrtBuff) = False Then
                MsgBox("检测到读卡器配置有问题！将恢复到默认设置", MsgBoxStyle.Exclamation, "警告")
                'result = RFIDLIB.Rfidlib_reader.RDR_LoadFactoryDefault(hreader)
                'If result = 0 Then
                '    Console.WriteLine("载入默认出厂设置")
                'End If
                Dim mSize = CType(wrtBuff.GetLength(0), UInteger)
                result = RFIDLIB.Rfidlib_reader.RDR_ConfigBlockWrite(hreader, 4, wrtBuff, mSize, 0)
                If result = 0 Then
                    Console.WriteLine("写入配置信息")
                End If
                result = RFIDLIB.Rfidlib_reader.RDR_ConfigBlockSave(hreader, 4)
                If result = 0 Then
                    Console.WriteLine("保存配置信息")
                End If
                'result = RFIDLIB.Rfidlib_reader.RDR_SystemReset(hreader)
                'If result = 0 Then
                '    Console.WriteLine("重启设备")
                'End If
                Call StartInventory()
            End If
        End If
    End Sub


    Public Sub Initialization()
        Dim e As New RFIDStatusEventArgs
        Dim connStrList As List(Of Dictionary(Of String, String)) = New List(Of Dictionary(Of String, String))

        RFIDLIB.Rfidlib_reader.RDR_LoadReaderDrivers("")
        Dim readerDriverInfoList As New ArrayList
        Dim nCount As UInteger = RFIDLIB.Rfidlib_reader.RDR_GetLoadedReaderDriverCount()
        Dim i As UInteger
        For i = 0 To nCount - 1
            Dim nSize As UInteger
            Dim driver As New RFIDLIB.CReaderDriverInf()
            Dim strCatalog As New StringBuilder()
            strCatalog.Append(ControlChars.NullChar, 64)

            nSize = CType(strCatalog.Capacity, UInteger)
            RFIDLIB.Rfidlib_reader.RDR_GetLoadedReaderDriverOpt(i, RFIDLIB.Rfidlib_def.LOADED_RDRDVR_OPT_CATALOG, strCatalog, nSize)
            driver.m_catalog = strCatalog.ToString()
            If driver.m_catalog = RFIDLIB.Rfidlib_def.RDRDVR_TYPE_READER Then
                ' Only reader we need
                Dim strName As New StringBuilder()
                strName.Append(ControlChars.NullChar, 64)
                nSize = CType(strName.Capacity, UInteger)
                RFIDLIB.Rfidlib_reader.RDR_GetLoadedReaderDriverOpt(i, RFIDLIB.Rfidlib_def.LOADED_RDRDVR_OPT_NAME, strName, nSize)
                driver.m_name = strName.ToString()
                Dim strProductType As New StringBuilder()
                strProductType.Append(ControlChars.NullChar, 64)
                nSize = CType(strProductType.Capacity, UInteger)
                RFIDLIB.Rfidlib_reader.RDR_GetLoadedReaderDriverOpt(i, RFIDLIB.Rfidlib_def.LOADED_RDRDVR_OPT_ID, strProductType, nSize)
                driver.m_productType = strProductType.ToString()

                Dim strCommSupported As New StringBuilder()
                strCommSupported.Append(ControlChars.NullChar, 64)
                nSize = CType(strCommSupported.Capacity, UInteger)
                RFIDLIB.Rfidlib_reader.RDR_GetLoadedReaderDriverOpt(i, RFIDLIB.Rfidlib_def.LOADED_RDRDVR_OPT_COMMTYPESUPPORTED, strCommSupported, nSize)
                driver.m_commTypeSupported = CType(Integer.Parse(strCommSupported.ToString()), UInteger)

                readerDriverInfoList.Add(driver)
            End If
        Next

        For i = 0 To readerDriverInfoList.Count - 1
            Dim drv As RFIDLIB.CReaderDriverInf = DirectCast(readerDriverInfoList(CInt(i)), RFIDLIB.CReaderDriverInf)
            If drv.m_commTypeSupported = RFIDLIB.Rfidlib_def.COMMTYPE_USB_EN Then
                Dim nUSBCnt As UInteger = RFIDLIB.Rfidlib_reader.HID_Enum(drv.m_name)
                For j = 0 To nUSBCnt - 1
                    'Dim usbName As New StringBuilder()
                    'usbName.Append(ControlChars.NullChar, 128)
                    'RFIDLIB.rfidlib_reader.HID_GetEnumItem(j, RFIDLIB.rfidlib_def.HID_ENUM_INF_TYPE_DRIVERPATH, usbName, CType(usbName.Capacity, UInteger))
                    'Debug.Print(usbName.ToString)
                    Dim SerialNumber As New StringBuilder()
                    SerialNumber.Append(ControlChars.NullChar, 64)
                    RFIDLIB.Rfidlib_reader.HID_GetEnumItem(j, RFIDLIB.Rfidlib_def.HID_ENUM_INF_TYPE_SERIALNUM, SerialNumber, CType(SerialNumber.Capacity, UInteger))
                    Dim connStr As New Dictionary(Of String, String) From {
                        {drv.m_name & "_" & SerialNumber.ToString, String.Format("RDType={0};CommType=USB;AddrMode=1;SerNum={1}", drv.m_name, SerialNumber.ToString)}
                    }
                    connStrList.Add(connStr)
                Next
            ElseIf drv.m_commTypeSupported = RFIDLIB.Rfidlib_def.COMMTYPE_COM_EN Then
                Dim nCOMCnt As UInteger = RFIDLIB.Rfidlib_reader.COMPort_Enum()
                For j = 0 To nCOMCnt - 1
                    Dim comName As New StringBuilder()
                    comName.Append(ControlChars.NullChar, 64)
                    RFIDLIB.Rfidlib_reader.COMPort_GetEnumItem(j, comName, CType(comName.Capacity, UInteger))
                    ConnString = String.Format("RDType={0};CommType=COM;COMName={1};BaudRate=38400;Frame=8E1;BusAddr=255", drv.m_name, comName.ToString)
                    Dim connStr As New Dictionary(Of String, String) From {
                        {drv.m_name & "_" & comName.ToString, String.Format("RDType={0};CommType=COM;COMName={1};BaudRate=38400;Frame=8E1;BusAddr=255", drv.m_name, comName.ToString)}
                    }
                    connStrList.Add(connStr)
                Next
            End If
        Next
        e.ConnStringList = connStrList
        RaiseEvent Status(Me, e)
    End Sub

    Private Function GetDrvInfo() As String
        Dim devInfor As New StringBuilder()
        devInfor.Append(ControlChars.NullChar, 128)
        Dim result As Integer = RFIDLIB.Rfidlib_reader.RDR_GetReaderInfor(hreader, 0, devInfor, CType(devInfor.Capacity, UInteger))
        If result = 0 Then
            Return devInfor.ToString
        End If
        Return Nothing
    End Function



    Public Sub ReadData(uid As Byte())
        Dim iret As Integer
        iret = RFIDLIB.Rfidlib_aip_iso15693.ISO15693_Connect(hreader, RFIDLIB.Rfidlib_def.RFID_ISO15693_PICC_ICODE_SLI_ID, 1, uid, hTag)
        If iret = 0 Then
            Dim result As String = ReadMultiBlocks(0, 2)
            While result Is Nothing
                result = ReadMultiBlocks(0, 2)
                Application.DoEvents()
            End While

            Dim e As New RFIDStatusEventArgs With {
                .Txt = "Q" & result
            }
            RaiseEvent Status(Me, e)

            iret = RFIDLIB.Rfidlib_reader.RDR_TagDisconnect(hreader, hTag)
            If iret = 0 Then
                hTag = 0
            End If


        End If


    End Sub


    ''' <summary>
    ''' 读某一个区信息
    ''' </summary>
    ''' <param name="postion">区编号</param>
    ''' <returns></returns>
    Private Function ReadOneBlock(ByVal postion As UInteger) As String
        Dim iret As Integer
        Dim SingleBuffer As Byte() = New Byte(3) {}
        Dim mSize = CType(SingleBuffer.GetLength(0), UInteger)
        Dim bytesBlkDatRead As UInteger
        iret = RFIDLIB.Rfidlib_aip_iso15693.ISO15693_ReadSingleBlock(hreader, hTag, 0, postion, SingleBuffer, mSize, bytesBlkDatRead)
        If iret = 0 Then
            Return BitConverter.ToString(SingleBuffer).Replace("-", String.Empty)
        End If
        Return Nothing
    End Function

    ''' <summary>
    ''' 读多个区
    ''' </summary>
    ''' <param name="begin">开始位置</param>
    ''' <param name="count">要读的块数量</param>
    ''' <returns></returns>
    Private Function ReadMultiBlocks(ByVal begin As UInteger, ByVal count As UInteger) As String
        Dim iret As Integer
        Dim dsfid As Byte, fafi As Byte, blkSize As Byte, blkNum As Byte, icref As Byte
        Dim uid As Byte() = New Byte(7) {}
        iret = RFIDLIB.Rfidlib_aip_iso15693.ISO15693_GetSystemInfo(hreader, hTag, uid, dsfid, fafi, blkSize, blkNum, icref)
        If iret = 0 Then
            If count > blkNum Then
                count = blkNum
            End If
            Dim bitLength As Integer = blkSize * (count - begin) - 1
            Dim BlockBuffer As Byte() = New Byte(bitLength) {}
            Dim nSize = CType(BlockBuffer.GetLength(0), UInteger)
            Dim bytesBlkDatRead As UInteger
            Dim blocksRead As UInteger
            iret = RFIDLIB.Rfidlib_aip_iso15693.ISO15693_ReadMultiBlocks(hreader, hTag, 0, begin, count, blocksRead, BlockBuffer, nSize, bytesBlkDatRead)
            If iret = 0 Then
                Return BitConverter.ToString(BlockBuffer).Replace("-", String.Empty)
            End If
        End If
        Return Nothing
    End Function
    Public Sub Beep()
        Dim bcount As Byte
        Dim rec = RFIDLIB.Rfidlib_reader.RDR_GetOutputCount(hreader, bcount)
        If rec = 0 Then
            For i = 1 To bcount
                Dim bf As New StringBuilder()
                bf.Append(ControlChars.NullChar, 64)
                Dim ir = RFIDLIB.Rfidlib_reader.RDR_GetOutputName(hreader, i, bf, CType(bf.Capacity, UInteger))
                Debug.Print(bf.ToString)
                Dim hOutputOperations = RFIDLIB.Rfidlib_reader.RDR_CreateSetOutputOperations()
                If hOutputOperations Then
                    RFIDLIB.Rfidlib_reader.RDR_AddOneOutputOperation(hOutputOperations, i, 3, 2, 1, 1)
                    RFIDLIB.Rfidlib_reader.RDR_SetOutput(hreader, hOutputOperations)
                    RFIDLIB.Rfidlib_data_node.DNODE_Destroy(hOutputOperations)
                End If
            Next
        End If

    End Sub

    Private Function ByteToString(bytes() As Byte) As String
        Dim s As New StringBuilder
        For Each bit As Byte In bytes
            If bit <> &H0 Then
                s.Append(ChrW(bit))
            End If
        Next
        Return s.ToString.TrimEnd
    End Function
End Class